//
// Created by 10413 on 2023/4/23.
//

#ifndef BIN_PACKING_SIMULATEDANNEALING_H
#define BIN_PACKING_SIMULATEDANNEALING_H
#include "../entity/NestPath.h"
#include <random>
#include <algorithm>
#include <chrono>
#include "../entity/Individual.h"
#include <QDebug>
#include <iostream>

class SimulatedAnnealing {
public:
    std::mt19937 rng_;
    std::uniform_int_distribution<int> rand_position; //[0, paths.size()-1]
    std::uniform_int_distribution<int> rand_angle; //[0, angleScale-1]
    std::uniform_real_distribution<double> rand_double;
    int paths_size;
    int angleScale;
    double t0; // 初始温度
    double alpha; // 降温系数
    double endTemp;
    int maxOuterIteration; // 总迭代次数
    int maxInnerIteration; // 每个温度下的最大抽样次数

    SimulatedAnnealing(int _paths_size, int _angleScale, double _t0, double _alpha, double _endTemp, int _max_out, int _max_inner) {
        rng_ = std::mt19937(std::chrono::system_clock::now().time_since_epoch().count());
        rand_double = std::uniform_real_distribution<double>(0.0, 1.0);
        paths_size = _paths_size;
        angleScale = _angleScale;
        rand_position = std::uniform_int_distribution<int>(0, _paths_size-1);
        rand_angle = std::uniform_int_distribution<int>(0, _angleScale-1);
        t0 = _t0; // 初始温度
        alpha = _alpha; // 降温系数
        endTemp = _endTemp;
        maxOuterIteration = _max_out; // 总迭代次数
        maxInnerIteration = _max_inner; // 每个温度下的最大抽样次数
    }

    /**
     * 交换位置
     * @param individual 原状态
     * @param swap_num 要交换的个数，默认为1
     * @return
     */
    Individual sa_swap(Individual& individual, int swap_num = 1) {
        std::vector<NestPath> paths = individual.paths;
        std::uniform_int_distribution<int> m_rand_int(0, paths_size-swap_num); //[0, paths_size-num]
        int i = m_rand_int(rng_);
        int j = m_rand_int(rng_);
        while(i==j)
            j = m_rand_int(rng_);
        for(int k = 0; k< swap_num;k++){
            std::swap(paths[i+k], paths[j+k]);
            int randAngle=(360.0/angleScale)*(rand_angle(rng_));
            paths[i].rotation = randAngle;
        }

        return {paths};
    }

    Individual sa_swap_neighbor(Individual& individual, int swap_num = 1) {
        std::vector<NestPath> paths = individual.paths;
        std::uniform_int_distribution<int> m_rand_int(0, paths_size-swap_num); //[0, paths_size-num]
        int i = m_rand_int(rng_);
        while(i==paths_size - swap_num)
            i = m_rand_int(rng_);
        int j = i + swap_num;
        for(int k = 0; k< swap_num;k++){
            std::swap(paths[i+k], paths[j+k]);
            int randAngle=(360.0/angleScale)*(rand_angle(rng_));
            // TODO:
//            std::cout<<"randAngle "<<randAngle<<endl;
            paths[i].rotation = randAngle;
        }

        return {paths};
    }

    // 将 paths[j] 插入到 paths[i] 前面
    Individual sa_insert(Individual& individual) {
        std::vector<NestPath> paths = individual.paths;
        std::uniform_int_distribution<int> rand_int(0, paths.size()-1); //[0, newPaths.size()-1]
        std::mt19937 rng_ = std::mt19937(std::chrono::system_clock::now().time_since_epoch().count());

        for (int i = 0; i < paths.size(); i++) {
            int j = rand_int(rng_);
            while (j == i)
                j = rand_int(rng_);
            NestPath tmp=paths[j];
            paths.erase(paths.begin()+j);
            paths.insert(paths.begin()+i, tmp);
            int randAngle=(360.0/4)*(rand_int(rng_));
            paths[i].rotation = randAngle;
        }

        return {paths};
    }

    enum updateType {
        Insert,
        Swap_Single,
        Swap_Small,
        Swap_media,
        Swap_large,
    };

    Individual createNewState(Individual& individual){
        // 随机选择一个变异函数类型
//        int type;
//        if (paths_size<30){
//            type = static_cast<updateType>(rand_double(rng_) * 2);
//        }else if(paths_size<100){
//            type = static_cast<updateType>(rand_double(rng_) * 3);
//        }else if(paths_size<300){
//            type = static_cast<updateType>(rand_double(rng_) * 4);
//        }else{
//            type = static_cast<updateType>(rand_double(rng_) * 5);
//        }

//        switch (type) {
//            case Insert:
//                return sa_insert(individual);
//            case Swap_Single:
//                return sa_swap(individual,1);
//            case Swap_Small:
//                return sa_swap(individual,3);
//            case Swap_media:
//                return sa_swap(individual,5);
//            case Swap_large:
//                return sa_swap(individual,7);
//        }
//        qDebug()<<R"(error in "createNewState" of "SimulatedAnnealing.h" )";
//        return individual;
        return sa_swap_neighbor(individual);

    }


};


#endif //BIN_PACKING_SIMULATEDANNEALING_H
